#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
#include <list>

// 定义消息包头
typedef struct {
    uint32_t msg_len;  // 消息体长度（网络字节序）
} msg_header_t;

typedef struct {
    int sock_conn;
    char ip[16];
    unsigned short port;
} client_info;

std::list<int> clients;
pthread_rwlock_t rwl;


void* client_communication(void* arg);
int send_packet(int sock, const char* data, int data_len);
int recv_packet(int sock, char* buf, int buf_size);


int main()
{
	pthread_rwlock_init(&rwl, NULL);

	// 第 1 步：创建监听套接字
	int sock_listen = socket(AF_INET, SOCK_STREAM, 0);

	if(sock_listen == -1)
	{
		perror("socket");
		exit(EXIT_FAILURE);
	}

	// 开启地址复用，以便服务器快速重启
	int opt_val = 1;
	setsockopt(sock_listen, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val));

	// 第 2 步：绑定地址
	struct sockaddr_in myaddr;
	myaddr.sin_family = AF_INET;                           // 指定地址家族为 Internet 地址家族
	//myaddr.sin_addr.s_addr = inet_addr("4.97.81.970");     // 指定要绑定的 IP 地址为本机的某个 IP 地址
	myaddr.sin_addr.s_addr = INADDR_ANY;                     // 指定要绑定的 IP 地址为本机任意 IP 地址
	myaddr.sin_port = htons(8888); // 指定要绑定的端口号

	if(bind(sock_listen, (struct sockaddr*)&myaddr, sizeof(myaddr)) == -1)
	{
		perror("bind");
		exit(EXIT_FAILURE);
	}

	// 第 3 步：监听
	if(listen(sock_listen, 5) == -1)
	{
		perror("listen");
		exit(EXIT_FAILURE);
	}

	// 设置超时时间为10秒
	struct timeval tv;
	tv.tv_sec = 10;     // 多少秒
	tv.tv_usec = 0;     // 多少微秒

	pthread_t tid;
	struct sockaddr_in client_addr;           // 用于接收客户端地址信息
	socklen_t addr_len = sizeof(client_addr); // 用于接收客户端地址信息的长度
	client_info* ci = NULL;
	int sock_conn;


	while(1)
	{
		// 第 4 步：接受客户端连接请求
		sock_conn = accept(sock_listen, (struct sockaddr*)&client_addr, &addr_len);  // 如果对客户端地址感兴趣，后两个参数就不要传 NULL

		if(sock_conn == -1)
		{
			perror("accept");
			continue;
		}

		/*
		if (setsockopt(sock_conn, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) 
		{
			perror("setsockopt");
		}
		*/

		printf("\n客户端(%s:%hu)连接成功！\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

		// 创建新线程，负责与客户端通信
		ci = (client_info*)malloc(sizeof(client_info));

		if(ci == NULL)
		{
			perror("malloc");
			close(sock_conn);
			continue;
		}

		ci->sock_conn = sock_conn;
		strcpy(ci->ip, inet_ntoa(client_addr.sin_addr));
		ci->port = ntohs(client_addr.sin_port);

		if(pthread_create(&tid, NULL, client_communication, ci))
		{
			perror("pthread_create");
			close(sock_conn);
			free(ci);
			continue;
		}
	}

	// 第 7 步：关闭监听套接字
	close(sock_listen);
}

// 发送带包头的数据包
int send_packet(int sock, const char* data, int data_len) {
    if(data_len <= 0 || data == NULL) {
        return -1;
    }
    
    // 构造包头
    msg_header_t header;
    header.msg_len = htonl(data_len);  // 转换为网络字节序
    
    // 先发送包头
    if(send(sock, &header, sizeof(header), 0) != sizeof(header)) {
        return -1;
    }
    
    // 再发送消息体
    if(send(sock, data, data_len, 0) != data_len) {
        return -1;
    }
    
    return 0;
}

// 接收完整数据包
int recv_packet(int sock, char* buf, int buf_size) {
    msg_header_t header;
    int bytes_received;
    
    // 第一步：接收包头
    bytes_received = 0;
    while(bytes_received < sizeof(header)) {
        int ret = recv(sock, (char*)&header + bytes_received, 
                      sizeof(header) - bytes_received, 0);
        if(ret <= 0) return ret;
        bytes_received += ret;
    }
    
    // 解析消息长度
    uint32_t msg_len = ntohl(header.msg_len);
    
    // 检查消息长度是否合法
    if(msg_len <= 0 || msg_len > buf_size - 1) {
        return -1;  // 消息长度不合法
    }
    
    // 第二步：接收消息体
    bytes_received = 0;
    while(bytes_received < msg_len) {
        int ret = recv(sock, buf + bytes_received, 
                      msg_len - bytes_received, 0);
        if(ret <= 0) return ret;
        bytes_received += ret;
    }
    
    buf[msg_len] = '\0';  // 添加字符串结束符
    return msg_len;
}

// 通信线程函数
void* client_communication(void* arg)
{
    client_info* ci = (client_info*)arg;
    pthread_detach(pthread_self());

    pthread_rwlock_wrlock(&rwl);
    // 客户端上线
    clients.push_back(ci->sock_conn);
    pthread_rwlock_unlock(&rwl);

    // 第 5 步：收发数据
    char msg[1001];
    int ret;

    while(1)
    {
        // 使用封包函数接收数据
        ret = recv_packet(ci->sock_conn, msg, sizeof(msg)-1);
        
        if(ret <= 0) break;

        printf("\n客户端(%s:%hu)说：%s\n", ci->ip, ci->port, msg);

        pthread_rwlock_rdlock(&rwl);
        for(int sock : clients)
        {
            if(sock != ci->sock_conn)  // 不发送给当前客户端
            {
                // 使用封包函数发送数据
                send_packet(sock, msg, ret);
            }
        }
        pthread_rwlock_unlock(&rwl);    
    }

    // 第 6 步：断开连接
    close(ci->sock_conn);
    printf("\n客户端(%s:%hu)断开连接！\n", ci->ip, ci->port);    

    pthread_rwlock_wrlock(&rwl);
    // 客户端下线
    clients.remove(ci->sock_conn);
    pthread_rwlock_unlock(&rwl);

    free(ci);
    return NULL;
}



int recv_line(int sock, char* buf, int maxlen)
{
	int n, rc;
	char c;
	for(n = 1; n < maxlen; n++)
	{
		if((rc = recv(sock, &c, 1, 0)) == 1)
		{
			if(c == '\n')
				break;

			*buf++ = c;
		}
		else if(rc == 0)
		{
			if(n == 1)
				return 0; // EOF, no data read
			else
				break;    // EOF, some data was read
		}
		else
		{
			return -1;    // error
		}
	}
	*buf = '\0';
	return n;
}
